package ipubsub

import (
	"context"
	"encoding/json"
	"github.com/go-redis/redis/v8"
	"github.com/sirupsen/logrus"
)

type NotifyType int

// 1,2,4,8,16,32,64
const (
	Default int = 1 << iota
	LRU         //2
)

// NotifyDTO 订阅发布消息体
type NotifyDTO struct {
	Type int    `zh:"通知类型" form:"type" json:"type"`
	Data string `zh:"数据, 统一用string，避免编程处理不当导致类型转换错误" form:"data" json:"data"`
}

type notifyPubSubService struct {
	Redis *redis.Client
}

// SubscribeHandler Subscribe 处理器接口 定义
type SubscribeHandler interface {
	HandleNotify(noticeDto NotifyDTO) error
}

func NewPubSubService(redis *redis.Client) *notifyPubSubService {
	return &notifyPubSubService{
		Redis: redis,
	}
}

// Publish 发布
func (this *notifyPubSubService) Publish(pubSubChannel string, dto *NotifyDTO) error {
	dtoStr, _ := json.Marshal(dto)
	ctx := context.Background()
	err := this.Redis.Publish(ctx, pubSubChannel, dtoStr).Err()
	logrus.Errorf("notify-Publish , key:%v, %v \n", pubSubChannel, err)
	return err
}

// Subscribe 订阅
func (this *notifyPubSubService) Subscribe(pubSubChannel string, subHandler SubscribeHandler) error {
	defer func() {
		if err := recover(); err != nil {
			logrus.Errorf("notify.Subscribe, recover err %v", err)
		}
	}()

	ctx := context.Background()
	pubSub := this.Redis.Subscribe(ctx, pubSubChannel)
	_, err := pubSub.Receive(ctx)
	if err != nil {
		logrus.Errorf("notify-Subscribe , key:%v, %v \n", pubSubChannel, err)
		return err
	}

	ch := pubSub.Channel()
	for msg := range ch {
		logrus.Infof("notify-Subscribe-msg: %s, %s \n", msg.Channel, msg.Payload)

		notice := NotifyDTO{}
		_ = json.Unmarshal([]byte(msg.Payload), &notice)
		err = subHandler.HandleNotify(notice)
		if err != nil {
			logrus.Errorf("notify handle error:%v \n", err)
		}
	}
	return nil
}
